



package wviz.gui.graph;

import prefuse.data.Graph;
import prefuse.data.Node;
import prefuse.data.Tuple;
import prefuse.data.event.TupleSetListener;
import prefuse.data.search.SearchTupleSet;
import prefuse.data.search.PrefixSearchTupleSet;
import prefuse.data.tuple.TupleSet;
import prefuse.Visualization;
import prefuse.Constants;
import prefuse.visual.VisualGraph;
import prefuse.visual.VisualItem;
import prefuse.visual.AggregateTable;
import prefuse.visual.AggregateItem;

import java.util.*;

/**
 * A spider display quite similiar to SpiderDispaly.
 * The only difference is that this class get aggregates (blobs in visualisation) from graph
 * <p/>
 *
 * @author Mohammad Asgari
 * @version 1.0
 * @date 12-Jan-2009
 */
public class SpiderDisplay2 extends SpiderDisplay{
    private static final String AGGREGATES_COLUMN_ID = "aggregates";

    public SpiderDisplay2(Graph g) {
        super(g);
    }

    public SpiderDisplay2(Graph g, int filterMaxValue, String filterLabel) {
        super(g, filterMaxValue, filterLabel);
    }

    @Override
    public void setupGraph(Graph g) {
        if (m_vis.getGroup(GRAPH) != null) {
            //group already added to this graph, remove it first
            m_vis.removeGroup(Visualization.SEARCH_ITEMS); //remove focus group
            m_vis.removeGroup(DOCUMENTS); //remove AggregateTable (i.e. blobs in visualisation)
            m_vis.removeGroup(GRAPH); //remove primary graph data nodes
        }
        VisualGraph vg = m_vis.addGraph(GRAPH, g);

        m_vis.setInteractive(EDGES, null, false);
        m_vis.setValue(NODES, null, VisualItem.SHAPE, Constants.SHAPE_DIAMOND);

        // Create the 'blobs' around nodes with lots of links.
        AggregateTable at = m_vis.addAggregates(DOCUMENTS);
        at.addColumn(VisualItem.POLYGON, float[].class);
        at.addColumn("id", int.class);

        Map<Integer, List<Node>> aggregates = new HashMap<Integer, List<Node>>(vg.getNodeCount() / 3);
        for (int i = 0; i < vg.getNodeCount(); i++) {
            Node node = vg.getNode(i);
            Object aggId = node.get(AGGREGATES_COLUMN_ID);
            if (aggId != null) {
                Integer aggregateId = (Integer) aggId;
                if (aggregateId == -1)
                    continue;

                List<Node> nodeList = aggregates.get(aggregateId);
                if (nodeList == null) {
                    nodeList = new ArrayList<Node>();
                }
                nodeList.add(node);
                aggregates.put(aggregateId, nodeList);
            }
        }

        for (Integer aggregate : aggregates.keySet()) {
            AggregateItem aitem0 = (AggregateItem) at.addItem();
            aitem0.setInt("id", aggregate);
            for (Node node : aggregates.get(aggregate)) {
                VisualItem visualItem = (VisualItem) node;
                aitem0.addItem(visualItem);
                //include all node neighbours
            }
        }


        render(aggregates.size());

        // Define focus groups
        TupleSet selected = m_vis.getFocusGroup(Visualization.SELECTED_ITEMS);
        SearchTupleSet search = new PrefixSearchTupleSet();
        m_vis.addFocusGroup(Visualization.SEARCH_ITEMS, search);

        // Hadi; not sure if this is actually required.
        selected.addTupleSetListener(new TupleSetListener() {
            public void tupleSetChanged(TupleSet t, Tuple[] add, Tuple[] rem) {
                m_vis.cancel("animate");
                m_vis.run("filter");
            }
        });

        // Modify the size of nodes depending on their number of links.
        TupleSet tupleSet = m_vis.getGroup(GRAPH);
        Iterator itr = tupleSet.tuples();
        while (itr.hasNext()) {
            Tuple tuple = (Tuple) itr.next();
            try {
                String word = tuple.getString("word");
                int links = tuple.getInt("links");
                if (word != null) {
                    tuple.setDouble(VisualItem.SIZE,
                            Math.min(tuple.getDouble(VisualItem.SIZE) *
                                    (1 + (links / 4.0)), MAX_NODE_FONT_SIZE));
                }

            } catch (Exception e) {
            }
        }
    }
}
